﻿using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Net.Public.ConnectState;
using Net.Public.EventSystem;
using Net.Public.Helper;
using Net.Public.Msg;


namespace Net.Public.Client
{
    public class WClient
    {
        private int id = -1;

        public int ID
        {
            get => id;
            set => id = value;
        }


        private Socket _client;
        public E_ConnectState connectState = E_ConnectState.Disconnected;
        private ConcurrentQueue<BaseMsg> _msgQueue;
        private MsgHandler _msgHandler;
        private ConcurrentQueue<BaseMsg> _sendMsgQueue;
        private string ip;
        private int port;

        public WClient(string ip, int port)
        {
            this.ip = ip;
            this.port = port;
            _msgHandler = new MsgHandler();
        }

        public void Start()
        {
            ConnectServer();
        }

        public void Close(bool reuseSocket = true)
        {
            if (connectState != E_ConnectState.Disconnected)
            {
                //停掉所有线程
                connectState = E_ConnectState.Disconnected;
                //不接收消息
                this._client.Shutdown(SocketShutdown.Both);
                //断开与远程端点的连接，但允许重新连接
                this._client.Disconnect(reuseSocket);
                Debugger.Log("客户端主动断开连接");
            }
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public void Dispose()
        {
            if (this._client == null) return;
            Close(false);
            this._client.Close();
            this._client = null;
            _msgQueue.Clear();
            _msgQueue = null;
            _sendMsgQueue.Clear();
            _sendMsgQueue = null;
            _msgHandler.Close();
            _msgHandler = null;
        }

        /// <summary>
        /// 向服务器发送消息
        /// </summary>
        /// <param name="msg"></param>
        public void SendMsgToServer(BaseMsg msg)
        {
            if (connectState == E_ConnectState.Connected)
            {
                try
                {
                    _sendMsgQueue.Enqueue(msg);
                }
                catch (Exception e)
                {
                    Debugger.Log(e.Message);
                    throw;
                }
            }
        }

        #region 内部实现

        private void ConnectServer()
        {
            connectState = E_ConnectState.Disconnected;
            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
            _client = new Socket(SocketType.Stream, ProtocolType.Tcp);
            _msgQueue = new();
            _sendMsgQueue = new();
            connectState = E_ConnectState.Connecting;
            _client.Connect(ipEndPoint);
            connectState = E_ConnectState.Connected;
            // 1.开启接收信息线程
            ThreadPool.QueueUserWorkItem(ReceiverMsgFromServer);
            // 2.开启接受信息处理线程
            ThreadPool.QueueUserWorkItem(ReceiveMsgHandler);
            // 3.开启发送信息线程
            ThreadPool.QueueUserWorkItem(SendMsgHandler);
        }

        private void SendMsgHandler(object? msg)
        {
            while (connectState == E_ConnectState.Connected)
            {
                try
                {
                    if (_sendMsgQueue.TryDequeue(out BaseMsg value))
                    {
                        _msgHandler.SendMsg(_client, value);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    Close(false);
                    throw new Exception("客户端发送信息异常");
                }
            }
        }

        private void ReceiverMsgFromServer(object? state)
        {
            while (connectState == E_ConnectState.Connected)
            {
                try
                {
                    if (_client.Available > 0)
                    {
                        byte[] result = new byte[1024 * 5];
                        int receiveNum = _client.Receive(result);
                        _msgHandler.ReceiveMsg(result, receiveNum);
                    }

                    (BaseMsg, bool) msg = _msgHandler.HandlerMsg();
                    if (msg.Item2)
                    {
                        _msgQueue.Enqueue(msg.Item1);
                    }
                }
                catch (Exception e)
                {
                    Debugger.Log(e.Message);
                    Close(true);
                    throw new Exception("接受服务器信息出现问题");
                }
            }
        }

        private void ReceiveMsgHandler(object? state)
        {
            while (connectState == E_ConnectState.Connected)
            {
                while (_msgQueue != null && _msgQueue.TryDequeue(out BaseMsg msg))
                {
                    RpcEventSystem.Instance.TriggerMsg(msg);
                }
            }
        }

        #endregion
    }
}